package cn.xutongxue.interview.controller;

import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import cn.xutongxue.interview.common.DeleteRequest;
import cn.xutongxue.interview.common.ResponseResult;
import cn.xutongxue.interview.constants.UserConstant;
import cn.xutongxue.interview.entity.QuestionBank;
import cn.xutongxue.interview.entity.QuestionBankMap;
import cn.xutongxue.interview.entity.dto.bank.BankQueryDto;
import cn.xutongxue.interview.entity.dto.bank.SingleAddQuestionToBankDto;
import cn.xutongxue.interview.entity.vo.bank.BankDetailVo;
import cn.xutongxue.interview.enums.Errors;
import cn.xutongxue.interview.service.QuestionBankMapService;
import cn.xutongxue.interview.service.QuestionBankService;
import cn.xutongxue.interview.utils.ThrowUtils;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jd.platform.hotkey.client.callback.JdHotKeyStore;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * 题库接口
 *
 * @author Administrator
 */
@RestController
@RequestMapping("/banks")
@Api(tags = "BankApi")
public class BanksController {
    @Resource
    private QuestionBankService questionBankService;
    @Resource
    private QuestionBankMapService questionBankMapService;

    /**
     * 分页查询题库
     *
     * @param bankQueryDto 分页查询条件
     * @return 查询结果
     */
    @ApiOperation("分页查询")
    @PostMapping("/list")
    @SentinelResource(value = "listBank")
    public ResponseResult<Page<QuestionBank>> listBank(@RequestBody BankQueryDto bankQueryDto) {
        ThrowUtils.throwIf(bankQueryDto == null, Errors.PARAMS_ERROR);
        ThrowUtils.throwIf(bankQueryDto.getPageSize() > 200, Errors.PARAMS_ERROR);
        LambdaQueryWrapper<QuestionBank> wrapper = Wrappers.lambdaQuery(QuestionBank.class)
                .like(StringUtils.isNotBlank(bankQueryDto.getTitle()), QuestionBank::getTitle, bankQueryDto.getTitle());
        Page<QuestionBank> page = questionBankService.page(new Page<>(bankQueryDto.getCurrent(), bankQueryDto.getPageSize()), wrapper);
        return ResponseResult.ok(page);
    }


    /**
     * 查询全部题库不分页
     *
     * @param bankQueryDto 查询条件
     * @return 查询结果
     */
    @ApiOperation("查询全部")
    @PostMapping("/all")
    public ResponseResult<List<QuestionBank>> allBank(@RequestBody BankQueryDto bankQueryDto) {
        ThrowUtils.throwIf(bankQueryDto == null, Errors.PARAMS_ERROR);
        LambdaQueryWrapper<QuestionBank> wrapper = Wrappers.lambdaQuery(QuestionBank.class)
                .like(StringUtils.isNotBlank(bankQueryDto.getTitle()), QuestionBank::getTitle, bankQueryDto.getTitle());
        return ResponseResult.ok(questionBankService.list(wrapper));
    }

    /**
     * 新增题库
     *
     * @param questionBank 待增加题库信息
     * @return 增加结果
     */
    @ApiOperation("新增题库")
    @PostMapping("/add")
    @SaCheckRole(UserConstant.USER_ROLE_ADMIN)
    public ResponseResult<Boolean> addBank(@RequestBody QuestionBank questionBank) {
        ThrowUtils.throwIf(questionBank == null, Errors.PARAMS_ERROR);
        long currentUserId = StpUtil.getLoginIdAsLong();
        // 设置创建用户ID
        questionBank.setUserId(currentUserId);
        return questionBankService.save(questionBank) ? ResponseResult.ok(true) : ResponseResult.fail("新增题库失败");
    }

    /**
     * 删除题库
     *
     * @param deleteRequest 待删除题库ID
     * @return 删除结果
     */
    @ApiOperation("删除题库")
    @PostMapping("/delete")
    @Transactional
    @SaCheckRole(UserConstant.USER_ROLE_ADMIN)
    public ResponseResult<Boolean> deleteBank(@RequestBody DeleteRequest deleteRequest) {
        ThrowUtils.throwIf(deleteRequest == null || deleteRequest.getId() == null, Errors.PARAMS_ERROR);
        LambdaQueryWrapper<QuestionBankMap> wrapper = Wrappers.lambdaQuery(QuestionBankMap.class)
                .eq(QuestionBankMap::getBankId, deleteRequest.getId());
        // 删除题库关联信息
        questionBankMapService.remove(wrapper);
        // 最后删除题库信息
        return questionBankService.removeById(deleteRequest.getId()) ? ResponseResult.ok(true) : ResponseResult.fail("删除题库失败");
    }

    /**
     * 修改题库信息
     *
     * @param questionBank 修改后的题库信息
     * @return 修改结果
     */
    @ApiOperation("修改题库信息")
    @PostMapping("/update")
    @SaCheckRole(UserConstant.USER_ROLE_ADMIN)
    public ResponseResult<Boolean> updateBank(@RequestBody QuestionBank questionBank) {
        ThrowUtils.throwIf(questionBank == null, Errors.PARAMS_ERROR);
        return questionBankService.updateById(questionBank) ? ResponseResult.ok(true) : ResponseResult.fail("修改题库失败");
    }

    /**
     * 根据id查询题库详情信息
     *
     * @param id 题库id
     * @return 题库详情
     */
    @ApiOperation("查询题库详情")
    @GetMapping("/queryDetail")
    public ResponseResult<BankDetailVo> queryBankDetailById(@RequestParam Long id) {
        ThrowUtils.throwIf(id == null || id < 0, Errors.PARAMS_ERROR);

        // hotkey 热key
        String key = "bank_detail_" + id;
        // 如果是热key
        if (JdHotKeyStore.isHotKey(key)) {
            Object cacheObj = JdHotKeyStore.get(key);
            if (cacheObj != null) {
                // 从缓存中获取值返回
                return ResponseResult.ok((BankDetailVo) cacheObj);
            }
        }

        BankDetailVo bankDetailVo = questionBankService.queryBankDetailById(id);
        // 设置本地缓存,只有是热key才需要设置缓存
        JdHotKeyStore.smartSet(key, bankDetailVo);

        return ResponseResult.ok(bankDetailVo);
    }

    @ApiOperation("添加单个题目到题库")
    @PostMapping("/add/single")
    public ResponseResult<Boolean> addSingleQuestionToBank(@RequestBody SingleAddQuestionToBankDto singleAddQuestionToBankDto) {
        ThrowUtils.throwIf(singleAddQuestionToBankDto == null, Errors.PARAMS_ERROR);
        Long bankId = singleAddQuestionToBankDto.getBankId();
        Long questionId = singleAddQuestionToBankDto.getQuestionId();
        questionBankService.addSingleQuestionToBank(bankId, questionId);
        return ResponseResult.ok(true);
    }
}
